summaryrefslogtreecommitdiffstats
path: root/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/DocumentsTree.java
blob: beb790ab18efda3702244f559d25d2c2b215ebb1 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
package org.yuzu.yuzu_emu.utils;

import android.content.Context;
import android.net.Uri;

import androidx.annotation.Nullable;
import androidx.documentfile.provider.DocumentFile;

import org.yuzu.yuzu_emu.YuzuApplication;
import org.yuzu.yuzu_emu.model.MinimalDocumentFile;

import java.util.HashMap;
import java.util.Map;
import java.util.StringTokenizer;

public class DocumentsTree {
    private DocumentsNode root;
    private final Context context;
    public static final String DELIMITER = "/";

    public DocumentsTree() {
        context = YuzuApplication.getAppContext();
    }

    public void setRoot(Uri rootUri) {
        root = null;
        root = new DocumentsNode();
        root.uri = rootUri;
        root.isDirectory = true;
    }

    public int openContentUri(String filepath, String openmode) {
        DocumentsNode node = resolvePath(filepath);
        if (node == null) {
            return -1;
        }
        return FileUtil.openContentUri(context, node.uri.toString(), openmode);
    }

    public long getFileSize(String filepath) {
        DocumentsNode node = resolvePath(filepath);
        if (node == null || node.isDirectory) {
            return 0;
        }
        return FileUtil.getFileSize(context, node.uri.toString());
    }

    public boolean Exists(String filepath) {
        return resolvePath(filepath) != null;
    }

    @Nullable
    private DocumentsNode resolvePath(String filepath) {
        StringTokenizer tokens = new StringTokenizer(filepath, DELIMITER, false);
        DocumentsNode iterator = root;
        while (tokens.hasMoreTokens()) {
            String token = tokens.nextToken();
            if (token.isEmpty()) continue;
            iterator = find(iterator, token);
            if (iterator == null) return null;
        }
        return iterator;
    }

    @Nullable
    private DocumentsNode find(DocumentsNode parent, String filename) {
        if (parent.isDirectory && !parent.loaded) {
            structTree(parent);
        }
        return parent.children.get(filename);
    }

    /**
     * Construct current level directory tree
     * @param parent parent node of this level
     */
    private void structTree(DocumentsNode parent) {
        MinimalDocumentFile[] documents = FileUtil.listFiles(context, parent.uri);
        for (MinimalDocumentFile document: documents) {
            DocumentsNode node = new DocumentsNode(document);
            node.parent = parent;
            parent.children.put(node.name, node);
        }
        parent.loaded = true;
    }

    public static boolean isNativePath(String path) {
        if (path.length() > 0) {
            return path.charAt(0) == '/';
        }
        return false;
    }

    private static class DocumentsNode {
        private DocumentsNode parent;
        private final Map<String, DocumentsNode> children = new HashMap<>();
        private String name;
        private Uri uri;
        private boolean loaded = false;
        private boolean isDirectory = false;

        private DocumentsNode() {}
        private DocumentsNode(MinimalDocumentFile document) {
            name = document.getFilename();
            uri = document.getUri();
            isDirectory = document.isDirectory();
            loaded = !isDirectory;
        }
        private DocumentsNode(DocumentFile document, boolean isCreateDir) {
            name = document.getName();
            uri = document.getUri();
            isDirectory = isCreateDir;
            loaded = true;
        }

        private void rename(String name) {
            if (parent == null) {
                return;
            }
            parent.children.remove(this.name);
            this.name = name;
            parent.children.put(name, this);
        }
    }
}